import {
  AmbientLight,
  BoxGeometry,
  DirectionalLight,
  GridHelper, Group, Material, Mesh, MeshBasicMaterial,
  MeshLambertMaterial,
  PerspectiveCamera,
  Scene, sRGBEncoding, Texture, TextureLoader,
  Vector3,
  WebGLRenderer,
} from 'three';
import {TrackballControls} from 'three/examples/jsm/controls/TrackballControls';
import {GLTF, GLTFLoader} from 'three/examples/jsm/loaders/GLTFLoader';
import {OBJLoader} from 'three/examples/jsm/loaders/OBJLoader';
import {FBXLoader} from 'three/examples/jsm/loaders/FBXLoader';
import {RoughnessMipmapper} from 'three/examples/jsm/utils/RoughnessMipmapper';

export class ModelRender {
  // 渲染器
  public renderer: WebGLRenderer;

  // 场景
  public scene: Scene;

  // 相机
  public camera: PerspectiveCamera;

  // 控制器
  public controls: TrackballControls;

  public cameraTarget: Vector3;

  private aspectRatio = 1;
  private cameraDefaults = {
    position: new Vector3(100, 100, 400),
    targetPosition: new Vector3(0, 0, 0),
    near: 0.01,
    far: 10000,
    fov: 45,
  };

  constructor(private canvas: HTMLCanvasElement) {
    this.cameraTarget = this.cameraDefaults.targetPosition;
  }

  public initDisplay(): void {
    this.initRenderer();
    this.initScene();
    this.initCamera();
    this.initControl();

    // GridHelper
    // const helper = new GridHelper(40, 40, 0xFF4444, 0x404040);
    // this.scene.add(helper);
  }

  /**
   * 重新计算画布比例
   */
  public reCalcAspectRatio(): void {
    this.aspectRatio = (this.canvas.clientWidth === 0) ? 1 : this.canvas.clientWidth / this.canvas.clientHeight;
  }

  /**
   * 调整画面
   */
  public resizeDisplay(): void {
    this.controls.handleResize();
    this.reCalcAspectRatio();
    this.renderer.setSize(this.canvas.offsetWidth, this.canvas.offsetHeight, false);
    this.updateCamera();
  }

  public render(): void {
    if (!this.renderer.autoClear) {
      this.renderer.clear();
    }

    this.controls.update();
    this.renderer.render(this.scene, this.camera);
  }

  public updateCamera(): void {
    this.camera.aspect = this.aspectRatio;

    // 摄像机注视方位
    this.camera.lookAt(this.cameraTarget);

    // 更新摄像机投影矩阵。在任何参数被改变以后必须被调用
    this.camera.updateProjectionMatrix();
  }

  public resetCamera(): void {
    this.camera.position.copy(this.cameraDefaults.position);
    this.cameraTarget.copy(this.cameraDefaults.targetPosition);
    this.updateCamera();
  }

  public initRenderer(): void {
    this.renderer = new WebGLRenderer({
      canvas: this.canvas,
      antialias: true, // 抗锯齿
      alpha: true,
    });
    this.renderer.outputEncoding = sRGBEncoding;
  }

  public initScene(): void {
    this.scene = new Scene();
  }

  public initCamera(): void {
    this.camera = new PerspectiveCamera(
      this.cameraDefaults.fov,
      this.aspectRatio,
      this.cameraDefaults.near,
      this.cameraDefaults.far,
    );
    this.resetCamera();
  }

  public initControl(): void {
    this.controls = new TrackballControls(this.camera, this.renderer.domElement);
    // 是否禁止缩放
    this.controls.noZoom = false;
    // 是否禁止旋转
    this.controls.noRotate = false;
    // 是否禁止平移
    this.controls.noPan = true;
  }

  public async initContent(): Promise<void> {
    try {
      const gltf = await this.loadGltfModel();
      gltf.scene.translateY(-100);
      this.scene.add(gltf.scene);
    } catch (e) {
      console.error(e);
    }
  }

  private loadGltfModel(): Promise<GLTF> {
    const loader = new GLTFLoader();

    return new Promise((resolve, reject) => {
      loader.load(
        'assets/matilda/scene.gltf',
        (obj) => {
          resolve(obj);
        },
        () => {
        },
        (e) => {
          reject(e);
        },
      );
    });
  }
}

